1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.lang3.builder;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertNull;
22  import org.junit.Test;
23  
24  /**
25   * Unit tests {@link org.apache.commons.lang3.builder.HashCodeBuilder}.
26   * 
27   * @version $Id$
28   */
29  public class HashCodeBuilderTest {
30  
31      /**
32       * A reflection test fixture.
33       */
34      static class ReflectionTestCycleA {
35          ReflectionTestCycleB b;
36  
37          @Override
38          public int hashCode() {
39              return HashCodeBuilder.reflectionHashCode(this);
40          }
41      }
42  
43      /**
44       * A reflection test fixture.
45       */
46      static class ReflectionTestCycleB {
47          ReflectionTestCycleA a;
48  
49          @Override
50          public int hashCode() {
51              return HashCodeBuilder.reflectionHashCode(this);
52          }
53      }
54  
55      // -----------------------------------------------------------------------
56  
57      @Test(expected=IllegalArgumentException.class)
58      public void testConstructorExZero() {
59          new HashCodeBuilder(0, 0);
60      }
61  
62      @Test(expected=IllegalArgumentException.class)
63      public void testConstructorExEvenFirst() {
64          new HashCodeBuilder(2, 3);
65      }
66      
67      @Test(expected=IllegalArgumentException.class)
68      public void testConstructorExEvenSecond() {
69          new HashCodeBuilder(3, 2);
70      }
71  
72      @Test(expected=IllegalArgumentException.class)
73      public void testConstructorExEvenNegative() {
74          new HashCodeBuilder(-2, -2);
75      }
76  
77      static class TestObject {
78          private int a;
79  
80          public TestObject(final int a) {
81              this.a = a;
82          }
83  
84          @Override
85          public boolean equals(final Object o) {
86              if (o == this) {
87                  return true;
88              }
89              if (!(o instanceof TestObject)) {
90                  return false;
91              }
92              final TestObject rhs = (TestObject) o;
93              return a == rhs.a;
94          }
95  
96          @Override
97          public int hashCode() {
98              return a;
99          }
100 
101         public void setA(final int a) {
102             this.a = a;
103         }
104 
105         public int getA() {
106             return a;
107         }
108     }
109 
110     static class TestSubObject extends TestObject {
111         private int b;
112 
113         @SuppressWarnings("unused")
114         transient private int t;
115 
116         public TestSubObject() {
117             super(0);
118         }
119 
120         public TestSubObject(final int a, final int b, final int t) {
121             super(a);
122             this.b = b;
123             this.t = t;
124         }
125 
126         @Override
127         public boolean equals(final Object o) {
128             if (o == this) {
129                 return true;
130             }
131             if (!(o instanceof TestSubObject)) {
132                 return false;
133             }
134             final TestSubObject rhs = (TestSubObject) o;
135             return super.equals(o) && b == rhs.b;
136         }
137 
138         @Override
139         public int hashCode() {
140             return b*17 + super.hashCode();
141         }
142 
143     }
144 
145     @Test
146     public void testReflectionHashCode() {
147         assertEquals(17 * 37, HashCodeBuilder.reflectionHashCode(new TestObject(0)));
148         assertEquals(17 * 37 + 123456, HashCodeBuilder.reflectionHashCode(new TestObject(123456)));
149     }
150 
151     @Test
152     public void testReflectionHierarchyHashCode() {
153         assertEquals(17 * 37 * 37, HashCodeBuilder.reflectionHashCode(new TestSubObject(0, 0, 0)));
154         assertEquals(17 * 37 * 37 * 37, HashCodeBuilder.reflectionHashCode(new TestSubObject(0, 0, 0), true));
155         assertEquals((17 * 37 + 7890) * 37 + 123456, HashCodeBuilder.reflectionHashCode(new TestSubObject(123456, 7890,
156                 0)));
157         assertEquals(((17 * 37 + 7890) * 37 + 0) * 37 + 123456, HashCodeBuilder.reflectionHashCode(new TestSubObject(
158                 123456, 7890, 0), true));
159     }
160 
161     @Test(expected=IllegalArgumentException.class)
162     public void testReflectionHierarchyHashCodeEx1() {
163         HashCodeBuilder.reflectionHashCode(0, 0, new TestSubObject(0, 0, 0), true);
164     }
165 
166     @Test(expected=IllegalArgumentException.class)
167     public void testReflectionHierarchyHashCodeEx2() {
168         HashCodeBuilder.reflectionHashCode(2, 2, new TestSubObject(0, 0, 0), true);
169     }
170 
171     @Test(expected=IllegalArgumentException.class)
172     public void testReflectionHashCodeEx1() {
173         HashCodeBuilder.reflectionHashCode(0, 0, new TestObject(0), true);
174     }
175 
176     @Test(expected=IllegalArgumentException.class)
177     public void testReflectionHashCodeEx2() {
178         HashCodeBuilder.reflectionHashCode(2, 2, new TestObject(0), true);
179     }
180 
181     @Test(expected=IllegalArgumentException.class)
182     public void testReflectionHashCodeEx3() {
183         HashCodeBuilder.reflectionHashCode(13, 19, null, true);
184     }
185 
186     @Test
187     public void testSuper() {
188         final Object obj = new Object();
189         assertEquals(17 * 37 + 19 * 41 + obj.hashCode(), new HashCodeBuilder(17, 37).appendSuper(
190                 new HashCodeBuilder(19, 41).append(obj).toHashCode()).toHashCode());
191     }
192 
193     @Test
194     public void testObject() {
195         Object obj = null;
196         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
197         obj = new Object();
198         assertEquals(17 * 37 + obj.hashCode(), new HashCodeBuilder(17, 37).append(obj).toHashCode());
199     }
200     
201     @Test
202     public void testObjectBuild() {
203         Object obj = null;
204         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append(obj).build().intValue());
205         obj = new Object();
206         assertEquals(17 * 37 + obj.hashCode(), new HashCodeBuilder(17, 37).append(obj).build().intValue());
207     }
208 
209     @Test
210     @SuppressWarnings("cast") // cast is not really needed, keep for consistency
211     public void testLong() {
212         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((long) 0L).toHashCode());
213         assertEquals(17 * 37 + (int) (123456789L ^ 123456789L >> 32), new HashCodeBuilder(17, 37).append(
214                 (long) 123456789L).toHashCode());
215     }
216 
217     @Test
218     @SuppressWarnings("cast") // cast is not really needed, keep for consistency
219     public void testInt() {
220         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((int) 0).toHashCode());
221         assertEquals(17 * 37 + 123456, new HashCodeBuilder(17, 37).append((int) 123456).toHashCode());
222     }
223 
224     @Test
225     public void testShort() {
226         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((short) 0).toHashCode());
227         assertEquals(17 * 37 + 12345, new HashCodeBuilder(17, 37).append((short) 12345).toHashCode());
228     }
229 
230     @Test
231     public void testChar() {
232         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((char) 0).toHashCode());
233         assertEquals(17 * 37 + 1234, new HashCodeBuilder(17, 37).append((char) 1234).toHashCode());
234     }
235 
236     @Test
237     public void testByte() {
238         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((byte) 0).toHashCode());
239         assertEquals(17 * 37 + 123, new HashCodeBuilder(17, 37).append((byte) 123).toHashCode());
240     }
241 
242     @Test
243     @SuppressWarnings("cast") // cast is not really needed, keep for consistency
244     public void testDouble() {
245         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((double) 0d).toHashCode());
246         final double d = 1234567.89;
247         final long l = Double.doubleToLongBits(d);
248         assertEquals(17 * 37 + (int) (l ^ l >> 32), new HashCodeBuilder(17, 37).append(d).toHashCode());
249     }
250 
251     @Test
252     @SuppressWarnings("cast") // cast is not really needed, keep for consistency
253     public void testFloat() {
254         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((float) 0f).toHashCode());
255         final float f = 1234.89f;
256         final int i = Float.floatToIntBits(f);
257         assertEquals(17 * 37 + i, new HashCodeBuilder(17, 37).append(f).toHashCode());
258     }
259 
260     @Test
261     public void testBoolean() {
262         assertEquals(17 * 37 + 0, new HashCodeBuilder(17, 37).append(true).toHashCode());
263         assertEquals(17 * 37 + 1, new HashCodeBuilder(17, 37).append(false).toHashCode());
264     }
265 
266     @Test
267     public void testObjectArray() {
268         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((Object[]) null).toHashCode());
269         final Object[] obj = new Object[2];
270         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
271         obj[0] = new Object();
272         assertEquals((17 * 37 + obj[0].hashCode()) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
273         obj[1] = new Object();
274         assertEquals((17 * 37 + obj[0].hashCode()) * 37 + obj[1].hashCode(), new HashCodeBuilder(17, 37).append(obj)
275                 .toHashCode());
276     }
277 
278     @Test
279     public void testObjectArrayAsObject() {
280         final Object[] obj = new Object[2];
281         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
282         obj[0] = new Object();
283         assertEquals((17 * 37 + obj[0].hashCode()) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
284         obj[1] = new Object();
285         assertEquals((17 * 37 + obj[0].hashCode()) * 37 + obj[1].hashCode(), new HashCodeBuilder(17, 37).append(
286                 (Object) obj).toHashCode());
287     }
288 
289     @Test
290     public void testLongArray() {
291         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((long[]) null).toHashCode());
292         final long[] obj = new long[2];
293         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
294         obj[0] = 5L;
295         final int h1 = (int) (5L ^ 5L >> 32);
296         assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
297         obj[1] = 6L;
298         final int h2 = (int) (6L ^ 6L >> 32);
299         assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append(obj).toHashCode());
300     }
301 
302     @Test
303     public void testLongArrayAsObject() {
304         final long[] obj = new long[2];
305         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
306         obj[0] = 5L;
307         final int h1 = (int) (5L ^ 5L >> 32);
308         assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
309         obj[1] = 6L;
310         final int h2 = (int) (6L ^ 6L >> 32);
311         assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
312     }
313 
314     @Test
315     public void testIntArray() {
316         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((int[]) null).toHashCode());
317         final int[] obj = new int[2];
318         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
319         obj[0] = 5;
320         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
321         obj[1] = 6;
322         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
323     }
324 
325     @Test
326     public void testIntArrayAsObject() {
327         final int[] obj = new int[2];
328         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
329         obj[0] = 5;
330         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
331         obj[1] = 6;
332         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
333     }
334 
335     @Test
336     public void testShortArray() {
337         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((short[]) null).toHashCode());
338         final short[] obj = new short[2];
339         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
340         obj[0] = (short) 5;
341         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
342         obj[1] = (short) 6;
343         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
344     }
345 
346     @Test
347     public void testShortArrayAsObject() {
348         final short[] obj = new short[2];
349         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
350         obj[0] = (short) 5;
351         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
352         obj[1] = (short) 6;
353         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
354     }
355 
356     @Test
357     public void testCharArray() {
358         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((char[]) null).toHashCode());
359         final char[] obj = new char[2];
360         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
361         obj[0] = (char) 5;
362         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
363         obj[1] = (char) 6;
364         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
365     }
366 
367     @Test
368     public void testCharArrayAsObject() {
369         final char[] obj = new char[2];
370         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
371         obj[0] = (char) 5;
372         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
373         obj[1] = (char) 6;
374         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
375     }
376 
377     @Test
378     public void testByteArray() {
379         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((byte[]) null).toHashCode());
380         final byte[] obj = new byte[2];
381         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
382         obj[0] = (byte) 5;
383         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
384         obj[1] = (byte) 6;
385         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append(obj).toHashCode());
386     }
387 
388     @Test
389     public void testByteArrayAsObject() {
390         final byte[] obj = new byte[2];
391         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
392         obj[0] = (byte) 5;
393         assertEquals((17 * 37 + 5) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
394         obj[1] = (byte) 6;
395         assertEquals((17 * 37 + 5) * 37 + 6, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
396     }
397 
398     @Test
399     public void testDoubleArray() {
400         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((double[]) null).toHashCode());
401         final double[] obj = new double[2];
402         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
403         obj[0] = 5.4d;
404         final long l1 = Double.doubleToLongBits(5.4d);
405         final int h1 = (int) (l1 ^ l1 >> 32);
406         assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
407         obj[1] = 6.3d;
408         final long l2 = Double.doubleToLongBits(6.3d);
409         final int h2 = (int) (l2 ^ l2 >> 32);
410         assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append(obj).toHashCode());
411     }
412 
413     @Test
414     public void testDoubleArrayAsObject() {
415         final double[] obj = new double[2];
416         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
417         obj[0] = 5.4d;
418         final long l1 = Double.doubleToLongBits(5.4d);
419         final int h1 = (int) (l1 ^ l1 >> 32);
420         assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
421         obj[1] = 6.3d;
422         final long l2 = Double.doubleToLongBits(6.3d);
423         final int h2 = (int) (l2 ^ l2 >> 32);
424         assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
425     }
426 
427     @Test
428     public void testFloatArray() {
429         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((float[]) null).toHashCode());
430         final float[] obj = new float[2];
431         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
432         obj[0] = 5.4f;
433         final int h1 = Float.floatToIntBits(5.4f);
434         assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
435         obj[1] = 6.3f;
436         final int h2 = Float.floatToIntBits(6.3f);
437         assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append(obj).toHashCode());
438     }
439 
440     @Test
441     public void testFloatArrayAsObject() {
442         final float[] obj = new float[2];
443         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
444         obj[0] = 5.4f;
445         final int h1 = Float.floatToIntBits(5.4f);
446         assertEquals((17 * 37 + h1) * 37, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
447         obj[1] = 6.3f;
448         final int h2 = Float.floatToIntBits(6.3f);
449         assertEquals((17 * 37 + h1) * 37 + h2, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
450     }
451 
452     @Test
453     public void testBooleanArray() {
454         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append((boolean[]) null).toHashCode());
455         final boolean[] obj = new boolean[2];
456         assertEquals((17 * 37 + 1) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
457         obj[0] = true;
458         assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
459         obj[1] = false;
460         assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
461     }
462 
463     @Test
464     public void testBooleanArrayAsObject() {
465         final boolean[] obj = new boolean[2];
466         assertEquals((17 * 37 + 1) * 37 + 1, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
467         obj[0] = true;
468         assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
469         obj[1] = false;
470         assertEquals((17 * 37 + 0) * 37 + 1, new HashCodeBuilder(17, 37).append((Object) obj).toHashCode());
471     }
472 
473     @Test
474     public void testBooleanMultiArray() {
475         final boolean[][] obj = new boolean[2][];
476         assertEquals(17 * 37 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
477         obj[0] = new boolean[0];
478         assertEquals(17 * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
479         obj[0] = new boolean[1];
480         assertEquals((17 * 37 + 1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
481         obj[0] = new boolean[2];
482         assertEquals(((17 * 37 + 1) * 37 + 1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
483         obj[0][0] = true;
484         assertEquals(((17 * 37 + 0) * 37 + 1) * 37, new HashCodeBuilder(17, 37).append(obj).toHashCode());
485         obj[1] = new boolean[1];
486         assertEquals(((17 * 37 + 0) * 37 + 1) * 37 + 1, new HashCodeBuilder(17, 37).append(obj).toHashCode());
487     }
488 
489     @Test
490     public void testReflectionHashCodeExcludeFields() throws Exception {
491         final TestObjectWithMultipleFields x = new TestObjectWithMultipleFields(1, 2, 3);
492 
493         assertEquals(((17 * 37 + 1) * 37 + 2) * 37 + 3, HashCodeBuilder.reflectionHashCode(x));
494 
495         assertEquals(((17 * 37 + 1) * 37 + 2) * 37 + 3, HashCodeBuilder.reflectionHashCode(x, (String[]) null));
496         assertEquals(((17 * 37 + 1) * 37 + 2) * 37 + 3, HashCodeBuilder.reflectionHashCode(x, new String[]{}));
497         assertEquals(((17 * 37 + 1) * 37 + 2) * 37 + 3, HashCodeBuilder.reflectionHashCode(x, new String[]{"xxx"}));
498 
499         assertEquals((17 * 37 + 1) * 37 + 3, HashCodeBuilder.reflectionHashCode(x, new String[]{"two"}));
500         assertEquals((17 * 37 + 1) * 37 + 2, HashCodeBuilder.reflectionHashCode(x, new String[]{"three"}));
501 
502         assertEquals(17 * 37 + 1, HashCodeBuilder.reflectionHashCode(x, new String[]{"two", "three"}));
503 
504         assertEquals(17, HashCodeBuilder.reflectionHashCode(x, new String[]{"one", "two", "three"}));
505         assertEquals(17, HashCodeBuilder.reflectionHashCode(x, new String[]{"one", "two", "three", "xxx"}));
506     }
507 
508     static class TestObjectWithMultipleFields {
509         @SuppressWarnings("unused")
510         private int one = 0;
511 
512         @SuppressWarnings("unused")
513         private int two = 0;
514 
515         @SuppressWarnings("unused")
516         private int three = 0;
517 
518         public TestObjectWithMultipleFields(final int one, final int two, final int three) {
519             this.one = one;
520             this.two = two;
521             this.three = three;
522         }
523     }
524 
525     /**
526      * Test Objects pointing to each other.
527      */
528     @Test
529     public void testReflectionObjectCycle() {
530         final ReflectionTestCycleA a = new ReflectionTestCycleA();
531         final ReflectionTestCycleB b = new ReflectionTestCycleB();
532         a.b = b;
533         b.a = a;
534         
535         // Used to caused:
536         // java.lang.StackOverflowError
537         // at java.lang.ClassLoader.getCallerClassLoader(Native Method)
538         // at java.lang.Class.getDeclaredFields(Class.java:992)
539         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:373)
540         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:349)
541         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)
542         // at
543         // org.apache.commons.lang.builder.HashCodeBuilderTest$ReflectionTestCycleB.hashCode(HashCodeBuilderTest.java:53)
544         // at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:422)
545         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:383)
546         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:349)
547         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)
548         // at
549         // org.apache.commons.lang.builder.HashCodeBuilderTest$ReflectionTestCycleA.hashCode(HashCodeBuilderTest.java:42)
550         // at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:422)
551 
552         a.hashCode();
553         assertNull(HashCodeBuilder.getRegistry());
554         b.hashCode();
555         assertNull(HashCodeBuilder.getRegistry());
556     }
557 
558     /**
559      * Ensures LANG-520 remains true
560      */
561     @Test
562     public void testToHashCodeEqualsHashCode() {
563         final HashCodeBuilder hcb = new HashCodeBuilder(17, 37).append(new Object()).append('a');
564         assertEquals("hashCode() is no longer returning the same value as toHashCode() - see LANG-520", 
565                      hcb.toHashCode(), hcb.hashCode());
566     }
567 
568 }